package com.gin.no_gay_alliance.activity;

import android.content.Intent;
import android.graphics.Rect;
import android.os.Message;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.CompoundButton;
import android.widget.EditText;

import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;

import com.gin.jackson.utils.JacksonUtils;
import com.gin.jackson.utils.ObjectUtils;
import com.gin.nga.callback.JsonCallback;
import com.gin.nga.client.NgaClient;
import com.gin.nga.enums.Hidden;
import com.gin.nga.exception.NgaClientException;
import com.gin.nga.exception.NgaException;
import com.gin.nga.method.PostApi;
import com.gin.nga.params.post.PostParam;
import com.gin.nga.params.post.PrepareParam;
import com.gin.nga.response.body.UploadBody;
import com.gin.nga.response.field.PostMessage;
import com.gin.nga.response.post.PostBody;
import com.gin.nga.response.post.PrepareBody;
import com.gin.no_gay_alliance.R;
import com.gin.no_gay_alliance.app.MyApplication;
import com.gin.no_gay_alliance.databinding.ActivityPostBinding;
import com.gin.no_gay_alliance.databinding.MergeToolbarBinding;
import com.gin.no_gay_alliance.exception.RequireParamException;
import com.gin.no_gay_alliance.fragment.post.BbsCodeFragment;
import com.gin.no_gay_alliance.fragment.post.TopicKeyFragment;
import com.gin.no_gay_alliance.fragment.post.attach.AttachmentFragment;
import com.gin.no_gay_alliance.fragment.post.attach.UploadFragment;
import com.gin.no_gay_alliance.fragment.post.attach.UploadedFragment;
import com.gin.no_gay_alliance.fragment.post.emote.EmoteFragment;
import com.gin.no_gay_alliance.manager.PostManager;
import com.gin.no_gay_alliance.param.PreparePostParam;
import com.gin.no_gay_alliance.utils.AlertDialogUtils;
import com.gin.no_gay_alliance.utils.EditTextUtils;
import com.gin.no_gay_alliance.utils.HandlerMessage;
import com.gin.no_gay_alliance.utils.InputMethodManagerUtils;
import com.gin.no_gay_alliance.utils.ViewUtils;
import com.gin.no_gay_alliance.viewmodel.InsertText;
import com.gin.no_gay_alliance.viewmodel.InsertTextCollapse;
import com.gin.no_gay_alliance.viewmodel.InsertTextUrl;
import com.gin.no_gay_alliance.viewmodel.PostResult;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import okhttp3.Call;

/**
 * 发帖活动 ViewBinding模式
 *
 * @author : ginstone
 * @version : v1.0.0
 * @since : 2023/8/26 14:12
 **/
public class PostActivity extends BaseBindingActivity<ActivityPostBinding> implements TabLayout.OnTabSelectedListener, TabLayoutMediator.TabConfigurationStrategy, ViewTreeObserver.OnGlobalLayoutListener, CompoundButton.OnCheckedChangeListener {
    public static final String TAG = PostActivity.class.getSimpleName();
    /**
     * 活动参数
     */
    PreparePostParam param;
    /**
     * 发帖准备参数
     */
    PrepareParam prepareParam;
    /**
     * 是否超过编辑时限
     */
    Boolean modifyAppend;
    /**
     * 是否正在发送回复
     */
    boolean sendingPost;
    TabLayoutMediator tabLayoutMediator;
    /**
     * 版面ID, 查询主题分类
     */
    Long forumId;
    /**
     * 附件列表
     */
    List<UploadBody> uploadBodyList = new ArrayList<>();


    UploadFragment.Args uploadArgs;
    UploadedFragment.Args uploadedArgs;
    /**
     * 是否发帖成功
     */
    boolean success = false;

    /**
     * 解析意图
     *
     * @param intent 意图
     */
    @Override
    protected void handleIntent(Intent intent) {
        param = intent.getParcelableExtra(PreparePostParam.class.getName());
        if (param == null) {
            throw new RequireParamException();
        }
    }

    /**
     * onCreate中的后续操作
     */
    @Override
    protected void onCreate() {
        // 只有新主题操作才显示单帖开关
        ViewUtils.setGone(param.action != PreparePostParam.Action.NEW, b.swReplyOnce);
        // 如果是编辑操作,隐藏匿名开关
        ViewUtils.setGone(param.action == PreparePostParam.Action.MODIFY, b.swAnonymous);
        // 引用警告
        ViewUtils.setGone(param.action != PreparePostParam.Action.QUOTE, b.tvWarning);
        // 如果是回复或引用，显示同步到动态开关
        ViewUtils.setGone(param.action != PreparePostParam.Action.QUOTE && param.action != PreparePostParam.Action.REPLY, b.swReplyFollowPush);
        // 开关切换回调
        ViewUtils.setOnCheckedChangeListener(this, b.swAnonymous, b.swReplyOnce, b.swHidden, b.swReplyFollowPush);
        // 根据活动参数生成准备参数
        prepareParam = param.buildParam();
        // 初始化下方工具栏
        initBottomToolbar();
        // 通过屏幕可用面积变化监听输入法状态变化
        getWindow().getDecorView().getViewTreeObserver().addOnGlobalLayoutListener(this);
        // 执行准备请求
        prepare();

    }


    /**
     * 装载右上角菜单
     *
     * @param menu         菜单
     * @param menuInflater 菜单渲染器
     */
    @Override
    protected void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
        // 发帖按钮
        menuInflater.inflate(R.menu.post_menu, menu);
    }

    /**
     * 配置tabLayout的每个标签
     *
     * @param tab      The Tab which should be configured to represent the title of the item at the given
     *                 position in the data set.
     * @param position The position of the item within the adapter's data set.
     */
    @Override
    public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
        switch (position) {
            case 0:
                tab.setIcon(R.drawable.ic_insert_emoticon_24);
                break;
            case 1:
                tab.setIcon(R.drawable.ic_code_24);
                break;
            case 2:
                tab.setIcon(R.drawable.ic_image_24);
                break;
            case 3:
                tab.setIcon(R.drawable.ic_topic_key_24);
                break;
            default:
                throw new RuntimeException("没有那个功能");
        }
    }

    @Override
    public boolean handleMessage(@NonNull Message message) {
        // 更新附件列表
        if (message.what == HandlerMessage.UPDATE_UPLOAD_BODY) {
            uploadBodyList = (List<UploadBody>) message.obj;
            return true;
        }
        // 插入文本
        if (message.what == HandlerMessage.INSERT_TEXT) {
            InsertText insertText = (InsertText) message.obj;
            EditTextUtils.insert(insertText.start, insertText.end, b.etContent, handler);
            b.etContent.requestFocus();
            return true;
        }
        // 插入折叠框
        if (message.what == HandlerMessage.INSERT_TEXT_COLLAPSE) {
            InsertTextCollapse textCollapse = (InsertTextCollapse) message.obj;
            // 正文框里是否选中了一段文字
            int selectionStart = b.etContent.getSelectionStart();
            int selectionEnd = b.etContent.getSelectionEnd();
            boolean hasSelection = selectionStart != selectionEnd;
            // 内容是否为空
            boolean emptyContent = ObjectUtils.isEmpty(textCollapse.content);
            String start = "".equals(textCollapse.title) ? "[collapse]" : String.format("[collapse=%s]", textCollapse.title);
            String end = "[/collapse]";
            // 标准格式输出
            String standard = start + textCollapse.content + end;

            if (hasSelection) {
                if (emptyContent) {
                    // 选中了 且 空内容: 将选中段作为内容
                    EditTextUtils.insert(start, end, b.etContent, handler);
                } else {
                    // 选中了 且 非空内容: 使用标准格式覆盖选中段
                    b.etContent.getText().replace(selectionStart, selectionEnd, standard);
                }
            } else {
                if (emptyContent) {
                    // 未选中 且 空内容 : 插入简易格式
                    EditTextUtils.insert(start, end, b.etContent, handler);
                } else {
                    // 未选中 且 非空内容 : 插入标准格式
                    EditTextUtils.insert(standard, null, b.etContent, handler);
                }
            }
            return true;
        }
        // 插入链接
        if (message.what == HandlerMessage.INSERT_TEXT_URL) {
            InsertTextUrl textUrl = (InsertTextUrl) message.obj;
            // 正文框里是否选中了一段文字
            int selectionStart = b.etContent.getSelectionStart();
            int selectionEnd = b.etContent.getSelectionEnd();
            boolean hasSelection = selectionStart != selectionEnd;
            // 标题是否为空
            boolean emptyTitle = ObjectUtils.isEmpty(textUrl.title);
            String start = String.format(Locale.CHINA, "[url=%s]", textUrl.url);
            String end = "[/url]";
            // 标准格式输出
            String standard = start + textUrl.title + end;

            if (hasSelection) {
                if (emptyTitle) {
                    // 选中了 且 空标题: 将选中段作为标题
                    EditTextUtils.insert(start, end, b.etContent, handler);
                } else {
                    // 选中了 且 非空标题: 使用标准格式覆盖选中段
                    b.etContent.getText().replace(selectionStart, selectionEnd, standard);
                }
            } else {
                if (emptyTitle) {
                    // 未选中 且 空标题 : 插入简易格式
                    EditTextUtils.insert(String.format(Locale.CHINA, "[url]%s[/url]", textUrl.url), null, b.etContent, handler);
                } else {
                    // 未选中 且 非空标题 : 插入标准格式
                    EditTextUtils.insert(standard, null, b.etContent, handler);
                }
            }
            return true;
        }
        // 插入主题分类
        if (message.what == HandlerMessage.INSERT_TOPIC_KEY) {
            EditTextUtils.insert(0, message.obj.toString(), b.etTitle, handler);
            return true;
        }
        return super.handleMessage(message);
    }

    /**
     * 如果布局中直接有toolbar, 在此提供, 如果使用Fragment布局中的toolbar,Fragment渲染完成后调用 setToolbar 方法装载
     *
     * @return toolbar toolbar
     */
    @Override
    protected Toolbar initToolbar() {
        return MergeToolbarBinding.bind(b.getRoot()).toolbar;
    }

    @Override
    protected void onResume() {
        super.onResume();
        // 设置toolbar标题
        setToolbarTitle(createToolbarTitle(param));
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        // 提交回复
        if (item.getItemId() == R.id.send_post) {
            sendPost();
        }
        return super.onOptionsItemSelected(item);
    }


    @Override
    protected void onPause() {
        super.onPause();
        PostManager postManager = MyApplication.app.managerFactory.getPostManager();
        if (success) {
            // 如果发帖成功 清空暂存数据
            postManager.removeTempData(prepareParam);
        } else {
            // 不成功，暂存数据
            postManager.saveTempData(prepareParam, b.etTitle.getText().toString(), b.etContent.getText().toString());
        }

    }

    /**
     * 当新tab被选中
     *
     * @param tab The tab that was selected
     */
    @Override
    public void onTabSelected(TabLayout.Tab tab) {
        boolean isGone = b.vp2.getVisibility() == View.GONE;
        b.vp2.setVisibility(View.VISIBLE);
        if (isGone) {
            // 如果是从隐藏状态拉起的,多触发一次选择
            uiDelayed(() -> b.vp2.setCurrentItem(tab.getPosition(), false), 200);
        }
        // 关闭输入法
        InputMethodManagerUtils.hide(b.etContent);
        InputMethodManagerUtils.hide(b.etTitle);
    }

    @Override
    public void onTabUnselected(TabLayout.Tab tab) {

    }

    /**
     * tab被重新选中(选中状态下被点击)
     *
     * @param tab The tab that was reselected.
     */
    @Override
    public void onTabReselected(TabLayout.Tab tab) {
        // 切换ViewPager2的可见状态
        if (b.vp2.getVisibility() == View.GONE) {
            this.onTabSelected(tab);
        } else if (b.vp2.getVisibility() == View.VISIBLE) {
            b.vp2.setVisibility(View.GONE);
        }
    }

    @Override
    public void onGlobalLayout() {
        // 如果激活了输入法，隐藏工具窗口
        uiDelayed(() -> {
            if (isShowing()) {
                b.vp2.setVisibility(View.GONE);
            }
        }, 200);
    }

    /**
     * 开关切换时的回调
     *
     * @param buttonView 开关
     * @param isChecked  是否选中
     */
    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        if (isChecked) {
            // 匿名警告
            if (buttonView == b.swAnonymous) {
                StringBuilder sb = new StringBuilder();
                if (param.action == PreparePostParam.Action.NEW) {
                    sb.append("匿名发布主题需要 5000 铜币\n\n");
                } else {
                    sb.append("匿名发布回复需要 100 铜币\n\n");
                }
                sb.append("匿名发布的内容如果违反版规将会 \n\n >> 加 重 处 罚 <<");
                AlertDialogUtils.showAlert(this, "匿名", sb.toString());
            }
            // 单帖说明
            if (buttonView == b.swReplyOnce) {
                AlertDialogUtils.showMessage(this, "单帖", "2000回复以内, 除楼主以外的用户只能回复一次", null);
            }
            // 隐藏说明
            if (buttonView == b.swHidden) {
                AlertDialogUtils.showMessage(this, "隐藏", "你的主题将只能被自己和版主看到(后续可编辑修改)", null);
            }
            // 同步动态说明
            if (buttonView == b.swReplyFollowPush) {
                AlertDialogUtils.showMessage(this, "同步到动态", "关注你的人将会在'关注动态'中收到推送", null);
            }
        }
    }

    /**
     * 初始化底部工具栏(Toolbar+ViewPager2)
     */
    private void initBottomToolbar() {
        // 禁止滑动ViewPager2
        b.vp2.setUserInputEnabled(false);
        b.vp2.setAdapter(new FragmentStateAdapter(this) {
            @NonNull
            @Override
            public Fragment createFragment(int position) {
                switch (position) {
                    case 0:
                        // 插入表情
                        return new EmoteFragment();
                    case 1:
                        return new BbsCodeFragment();
                    case 2:
                        return AttachmentFragment.newInstance(uploadArgs, uploadedArgs);
                    case 3:
                        return TopicKeyFragment.newInstance(forumId);
                    default:
                        throw new RuntimeException("没有那个功能");
                }
            }

            @Override
            public int getItemCount() {
                return 4;
            }
        });
        // 绑定tabLayout和ViewPager2
        tabLayoutMediator = attachTabLayout(tabLayoutMediator, b.tabLayout, b.vp2);
        // tabLayout的tab点击事件
        b.tabLayout.addOnTabSelectedListener(this);
    }

    /**
     * 准备完成的回调
     *
     * @param body 响应
     */
    private void onPrepared(PrepareBody body) {
        JacksonUtils.print(body);

        // 标记是否编辑超时, 超时的正文内容将被添加到原文后方
        modifyAppend = body.getModifyAppend();
        modifyAppend = modifyAppend != null ? modifyAppend : false;

        // 上传附件用到的参数
        uploadArgs = new UploadFragment.Args(body);
        // 管理已上传附件用到的参数
        uploadedArgs = new UploadedFragment.Args(body);
        // 查询主题分类用到的参数
        forumId = body.getForumId();
        // 显示tabLayout
        ui(() -> b.tabLayout.setVisibility(View.VISIBLE));


        // 操作UI
        ui(() -> {
            // 是否隐藏
            b.swHidden.setChecked(body.getHidden() != null ? body.getHidden() : false);
            // 如果未超过编辑时限, 添加正文
            if (!modifyAppend) {
                b.etContent.setText(body.getContent());
            }
            //设置标题
            b.etTitle.setText(body.getTitle());

            // 设置界面元素可用
            ViewUtils.setEnable(true, b.etTitle, b.etContent, b.swHidden, b.swAnonymous, b.swReplyOnce, b.swReplyFollowPush);

            // 检查datastore暂存数据,如果有暂存数据,使用之覆盖标题和正文
            PostManager postManager = MyApplication.app.managerFactory.getPostManager();
            PostManager.TempData tempData = postManager.getTempData(prepareParam);
            if (tempData != null) {
                b.etContent.setText(tempData.content);
                b.etTitle.setText(tempData.title);
            }


            // 获取焦点 启动输入法
            EditText target = param.action == PreparePostParam.Action.NEW ? b.etTitle : b.etContent;
            // 获取焦点
            target.requestFocus();
            if (!ObjectUtils.isEmpty(target.getText())) {
                // 把光标设置到末尾
                target.setSelection(target.getText().length());
            }
            // 启动输入法
            InputMethodManagerUtils.show(handler, target);
        });
    }

    /**
     * 生成准备参数，执行准备请求
     */
    private void prepare() {
        NgaClient client = MyApplication.getClient();

        PostApi.prepare(client, prepareParam).async(new JsonCallback<PrepareBody>() {
            @Override
            public void onSuccess(PrepareBody body) {
                onPrepared(body);
            }

            @Override
            public void handleException(NgaException e) {
                super.handleException(e);
                if (e instanceof NgaClientException) {
                    // 报错提示，关闭活动
                    String msg = ((NgaClientException) e).getReason().get(0);
                    toast(msg);
                    uiDelayed(() -> finish(), 1000);
                }
            }
        });
    }

    /**
     * 发送回复
     */
    private void sendPost() {
        if (sendingPost) {
            toast("正在提交,请稍等...");
            return;
        }
        sendingPost = true;
        // 发送回复
        NgaClient client = MyApplication.getClient();

        String title = b.etTitle.getText().toString();
        String content = b.etContent.getText().toString();
        Hidden hidden = b.swHidden.isChecked() ? Hidden.HIDDEN : Hidden.CANCEL;
        PostParam postParam = new PostParam(title, content, modifyAppend, hidden, b.swAnonymous.isChecked(), b.swReplyOnce.isChecked(), b.swReplyFollowPush.isChecked());
        // 添加附件列表
        postParam.addAll(uploadBodyList);
        JacksonUtils.printPretty(postParam);
        PostApi.send(client, prepareParam, postParam).async(new JsonCallback<PostBody>() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                super.onFailure(call, e);
                toastLong(e.getMessage());
                sendingPost = false;
            }

            @Override
            public void onSuccess(PostBody body) {
                PostMessage data = body.getData();
                sendingPost = false;
                if (data != null) {
                    //提示
                    String message = data.getMessage();
                    if (message != null) {
                        int index = message.indexOf("你因在发帖时");
                        if (index > -1) {
                            toast(message.substring(0, index));
                            toast(message.substring(index));
                        } else {
                            toast(message);
                        }

                        // 标题有问题
                        if (message.contains("标题")) {
                            EditTextUtils.focus(PostActivity.this, b.etTitle, handler);
                        }
                    }


                    // 发帖成功，返回结果，结束活动
                    if (data.getCode() == 200 && data.getLocation() != null) {
                        success = true;
                        setResult(200, new PostResult(data.getLocation()).buildIntent());
                        finish();
                    }
                }

            }

            /**
             * 处理异常
             *
             * @param e 异常
             */
            @Override
            public void handleException(NgaException e) {
                sendingPost = false;
                super.handleException(e);
                if (e instanceof NgaClientException) {
                    String message = ((NgaClientException) e).getReason().get(1);
                    toast(message);
                }
            }
        });
    }

    /**
     * 根据参数确定toolbar标题
     *
     * @param param 参数
     * @return 标题
     */
    private static String createToolbarTitle(PreparePostParam param) {
        switch (param.action) {
            case NEW:
                return "新主题";
            case MODIFY:
                return "修改";
            case QUOTE:
                return "引用";
            case REPLY:
                return param.isComment ? "评论" : "回复";
            default:
                throw new RuntimeException("非法的Action");
        }
    }

    private boolean isShowing() {
        // 获取当前屏幕内容的高度
        int screenHeight = getWindow().getDecorView().getHeight();

        // 获取View可见区域的bottom
        Rect rect = new Rect();
        getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
        return screenHeight * 3 > rect.bottom * 4;
    }
}
